/*******************************************************************************
 *	                           ui spi
 * 用于驱动 HC595/H165 级联IO扩展
 *******************************************************************************/
#include "bsp.h"
#include "pincfg.h"
#include "nor_cmd.h"
#include "framework.h"
#include "bsp_ui_spi.h"

#define SPIX SPI2
#define ISR_IRQn SPI2_IRQn
#define ISR SPI2_IRQHandler

/*****************************************************************************
 * @brief   fun
 *****************************************************************************/
obj_init_app(ui_update_init);
void ui_spi_start(void);

/*****************************************************************************
 * @brief   var
 *****************************************************************************/
ui_spi_obj_type ui_spi_obj;

/*****************************************************************************
 * @brief   操作时序
 * 定时中断  | - - - - - - - - - -
 * 字        L1 L2 00 00
 * CS       ↑  ↓  ↑     ↓
 * K                 D0 D1
 *****************************************************************************/

/*****************************************************************************
 * @brief   hal init.
 * @param   none
 * @return  none
 * @ Pass/ Fail criteria: none
 *****************************************************************************/
void ui_spi_init(void)
{
	spi_init_type cfg;
	int cnt;
	volatile uu16 datr;

	// 初始化配置
	cfg.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
	cfg.clock_phase = SPI_CLOCK_PHASE_2EDGE;
	cfg.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
	cfg.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
	cfg.first_bit_transmission = SPI_FIRST_BIT_MSB;
	cfg.frame_bit_num = SPI_FRAME_16BIT;
	cfg.master_slave_mode = SPI_MODE_MASTER;
	cfg.mclk_freq_division = SPI_MCLK_DIV_512;

	spi_init(SPIX, &cfg);

	// 开启接收完成中断
	nvic_irq_set(ISR_IRQn, 3, EXT_TRUE);
	SPIX->ctrl2_bit.rdbfie = 1;
	SPIX->ctrl1_bit.spien = 1;

	// 启动发送
	memset(&ui_spi_obj, 0, sizeof(ui_spi_obj));

	// 发送空闲状态数据
	cnt = 2;
	while (cnt--)
	{
		SPIX->dt = 0;
		while (!SPIX->sts_bit.rdbf)
			;
		datr = SPIX->dt;
	}

	// 输出脉冲
	ui_spi_cs.dis();
	cnt = 100;
	while (cnt--)
	{
		NOP20();
	}
	ui_spi_cs.en();
}

/*****************************************************************************
 * @brief   update init
 *****************************************************************************/
void ui_update_init(void)
{
	app_timer_task_add(ui_spi_start);
	ui_spi_obj.tx_buff[0] = 0xFFFF;
	ui_spi_obj.tx_buff[1] = 0xFFFF;
	ui_spi_obj.comp = 1;
}

/*****************************************************************************
 * @brief   isr.
 * @param   none
 * @return  none
 * @ Pass/ Fail criteria: none
 *****************************************************************************/
void ISR(void)
{
	volatile uu16 rdat;

	(void)rdat;
	ui_spi_obj.index++;

	switch (ui_spi_obj.index)
	{
	case 1:
		// 发送第二个显示数据
		rdat = SPIX->dt;
		ui_spi_cs.dis();
		SPIX->dt = ui_spi_obj.tx_buff[ui_spi_obj.index];
		break;
	case 2:
		// 发送第二个显示数据
		rdat = SPIX->dt;
		ui_spi_cs.dis();
		SPIX->dt = ui_spi_obj.tx_buff[ui_spi_obj.index];
		break;
	case 3:
		rdat = SPIX->dt;
		// 锁存显示数据和键值
		ui_spi_cs.en();
		// 发送关断数据，开始接收键值
		SPIX->dt = 0x00;
		break;
	case 4:
		// 发送关断数据，并接收键值
		ui_spi_obj.rx_buff[0] = (~SPIX->dt) & 0xE7E7;
		SPIX->dt = 0x00;
		break;
	case 5:
		// 发送关断数据，并接收键值
		ui_spi_obj.rx_buff[1] = (~SPIX->dt) & 0xE7E7;
		SPIX->dt = ui_spi_obj.tx_buff[2];
		break;
	case 6:
		// 接收第二键
		ui_spi_obj.rx_buff[2] = (~SPIX->dt) & 0xE7E7;
		ui_spi_cs.dis();

		// 发送完成
		ui_spi_obj.comp = 1;
		break;
	default:
		rdat = SPIX->dt;
		break;
	}
}

/*****************************************************************************
 * @brief   spi start
 * @param   none
 * @return  none
 * @ Pass/ Fail criteria: none
 *****************************************************************************/
void ui_spi_start(void)
{
	if (ui_spi_obj.comp)
	{
		// 锁存数据
		ui_spi_cs.en();

		// 开始发送
		ui_spi_obj.comp = 0;
		ui_spi_obj.index = 0;

		// 发送第一个显示数据
		SPIX->dt = ui_spi_obj.tx_buff[ui_spi_obj.index];
	}
	else
	{
		NOP1();
	}
}
